package imse.team0.processors;

import imse.team0.db.dal.LocalInventoryQueryService;
import imse.team0.inventoryws.*;
import imse.team0.orders.Order;
import imse.team0.orders.SplitOrderItem;
import org.apache.camel.Body;
import org.apache.camel.Exchange;
import org.apache.camel.Header;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: Evgenia
 * Date: 4/28/12
 * Time: 11:15 PM
 * To change this template use File | Settings | File Templates.
 */
public class OrderProcessing {
    private static Logger LOG = LoggerFactory.getLogger(OrderProcessing.class.getName());
    // out of stock will be = > 200
    private static int outofstockQuantity = 0;
    private static Map<String, Integer> itemsToRefill = new HashMap<String, Integer>();
    private LocalInventoryQueryService queryService = new LocalInventoryQueryService();

    public List<SplitOrderItem> splitOrderItems(@Body Order incomingOrder) {
        List<SplitOrderItem> splitOrderItems = new ArrayList<SplitOrderItem>();
        List<Order.OrderItem> orderItems = incomingOrder.items;
        for (Order.OrderItem orderItem : orderItems) {
            SplitOrderItem splitOrderItem = new SplitOrderItem(orderItem.itemId, orderItem.quantity,
                    incomingOrder.orderid,
                    incomingOrder.clientID,
                    incomingOrder.receiptTime);
            splitOrderItems.add(splitOrderItem);
        }
        return splitOrderItems;
    }

    // verifyInventoryOrderItems
    public void removeRequestedQuantity(
            @Body SplitOrderItem incomingSplitOrderItem, Exchange exchange) throws imse.team0.processors.exceptions.NotAvailableException {
        // in future here will be query to DB
        // to find out the available quantity of the order item
        // now the requested quantity is equal to available one

        try {

            int numberOfItems = queryService.removeItem(incomingSplitOrderItem.itemId, incomingSplitOrderItem.quantity);
            if (numberOfItems < incomingSplitOrderItem.quantity) // there are low inventory items in the database
            {
                final int missingQuantity = incomingSplitOrderItem.quantity - numberOfItems;
                outofstockQuantity = outofstockQuantity + missingQuantity;
                LOG.debug("------------->Requested order item with id="+incomingSplitOrderItem.itemId+" and quantity="+incomingSplitOrderItem.quantity+" could not be booked in local inventory. Rollback the whole order processing.");
                Integer qty;
                synchronized (OrderProcessing.class) {
                    qty = itemsToRefill.get(incomingSplitOrderItem.itemId);
                    if (qty == null) {
                        itemsToRefill.put(incomingSplitOrderItem.itemId, new Integer(missingQuantity));
                    } else {
                        qty = qty.intValue() + missingQuantity;
                        itemsToRefill.put(incomingSplitOrderItem.itemId, qty);
                    }
                }

                OrderBookStatus status = null;
                if (outofstockQuantity >= 200) {
                    synchronized (OrderProcessing.class) {
                        if (outofstockQuantity >= 200) {
                            // TODO: call replenishment service
                            LOG.debug("------------->Must replenish now: " + outofstockQuantity + " were not sold!");
                            WarehouseInventoryService service = new WarehouseInventoryService();
                            WarehousePortType servicePort = service.getInventoryServicePort();
                            ReplenishRequest parameters = new ReplenishRequest();
                            parameters.setLocalInventoryID("LOCAL_INVENTORY_1");
                            List<OrderItem> itemsToUpdate = parameters.getReplenishItems();
                            for (String itemId : itemsToRefill.keySet()) {
                                OrderItem item = new OrderItem();
                                item.setItemId(itemId);
                                item.setQuantity(itemsToRefill.get(itemId));
                                itemsToUpdate.add(item);
                            }
                            try {
                                status = servicePort.replenishRequest(parameters).getOrderStatus();
                                outofstockQuantity = 0;
                                itemsToRefill.clear();
                                // check to see how many units to put now in the database..
                                for (AvailableUnit item : status.getOrderItems()) {
                                    try {
                                        queryService.addItem(item.getId(), item.getAvailable());
                                    } catch (Exception e) {
                                        throw new RuntimeException("local inventory database is probably down...", e);
                                    }
                                }
                                // TODO: NOTE: we do not check if actually less items are returned cause there is nothing we can do about that...
                            } catch (NotAvailableException_Exception e) {
                                new RuntimeException("Database for global inventory is down...", e);
                            }
                        }
                    }
                }
                // here we have to stop the splitter on this item
                // and also have to send the whole order to the warehouse for processing
                /// exchange.getOut().setHeader("Stop", "NOT_AVAILABLE");
                /// exchange.getOut().setBody(incomingSplitOrderItem);
                /// exchange.getOut().setHeader("OrderID", incomingSplitOrderItem.orderid);
                throw new imse.team0.processors.exceptions.NotAvailableException(incomingSplitOrderItem.orderid);
            /*} else {
                    // TODO: process with transportation and invoice parts
                    // Send to transportation company 1.volume of load; 2.start_address; 3.end_address;
              */
            }
        } catch (Exception e) {
            // assume the DB is available all the time
            e.printStackTrace();
        }


        exchange.getOut().setBody(incomingSplitOrderItem);
        exchange.getOut().setHeader("OrderID", incomingSplitOrderItem.orderid);
        LOG.debug("Remove item: id=" + incomingSplitOrderItem.itemId + " qty=" + incomingSplitOrderItem.quantity);
    }

    public void cancelOrderFromLocalInventory(@Header(value = "RollbackIDList") List<String> idlist, @Body Order order) {
        List<Order.OrderItem> orderItems = order.items;
        for (String itemId : idlist) {
            for (Order.OrderItem orderItem : orderItems) {
                if (orderItem.itemId == itemId) {
                    try {
                        queryService.addItem(itemId, orderItem.quantity);
                    } catch (Exception e) {
                        // assume the DB is available all the time
                        e.printStackTrace();
                    }
                }
            }

        }
    }
}
